Reusable Components and React Best Practices in React Native
Course: React Native Training
Topic: Reusable Components and React Best Practices
Course Link: React Native Training Course
Demo Link: Register for a Course Demo
JustAcademy Website: Visit JustAcademy
1. Introduction to Reusable Components
Reusable components are independent UI building blocks that can be used in multiple places within a React Native application. Instead of writing the same interface and logic repeatedly, developers create a component once and reuse it wherever needed. React Native uses React components to organize mobile interfaces into smaller, composable units. Read the official React Native Components documentation.
For example, an application may contain buttons for logging in, submitting a form, saving a profile, and adding an item to a cart. Rather than implementing each button separately, developers can create a reusable Button component that provides consistent styling and behavior.
1.1 What Is a Component?
A component is typically a JavaScript function that returns JSX describing part of the user interface. React Native components use elements such as View, Text, Image, TextInput, and Pressable.
import React from 'react';
import { View, Text } from 'react-native';
function WelcomeMessage() {
return (
<View>
<Text>Welcome to React Native!</Text>
</View>
);
}
export default WelcomeMessage;
Here, WelcomeMessage is a functional component that can be imported and displayed in different screens.
1.2 Benefits of Reusable Components
- Code reuse: Implement a UI pattern once and reuse it in multiple places.
- Consistency: Maintain a common appearance and behavior across screens.
- Maintainability: Update shared UI in one place rather than editing multiple copies.
- Readability: Break large screens into smaller, understandable parts.
- Testability: Test components and their behavior independently when practical.
- Scalability: Organize an application so that adding features becomes easier.
- Collaboration: Team members can work on separate components with clearly defined responsibilities.
2. Creating and Using Reusable Components
A good starting point is to identify UI elements that appear repeatedly or represent a clear, independent responsibility.
2.1 Create a Component
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
function UserCard() {
return (
<View style={styles.card}>
<Text style={styles.name}>Aarav Sharma</Text>
<Text>React Native Developer</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
marginVertical: 8,
borderRadius: 10,
backgroundColor: '#FFFFFF',
elevation: 2
},
name: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 4
}
});
export default UserCard;
2.2 Use the Component in Another Screen
import React from 'react';
import { View } from 'react-native';
import UserCard from './components/UserCard';
export default function App() {
return (
<View style={{ padding: 16 }}>
<UserCard />
<UserCard />
</View>
);
}
Both instances use the same component implementation. If the shared card design changes, update the UserCard component instead of changing every screen that uses it.
2.3 When Should You Create a Reusable Component?
- When the same UI pattern appears on multiple screens.
- When a section has a clear purpose and can be understood independently.
- When a complex screen would be easier to read if divided into smaller components.
- When a visual pattern requires consistent styling and behavior.
- When a piece of UI needs independent testing or accessibility improvements.
Avoid creating a separate component for every tiny JSX element without a clear benefit. Reuse should make code simpler rather than introduce unnecessary complexity.
3. Understanding Props in Reusable Components
Props, short for properties, allow a parent component to pass data and configuration to a child component. They make a component flexible because the same component can display different content without duplicating its implementation.
3.1 Passing Props
import React from 'react';
import { Text } from 'react-native';
function Greeting({ name }) {
return <Text>Hello, {name}!</Text>;
}
export default function App() {
return (
<>
<Greeting name="Aarav" />
<Greeting name="Priya" />
</>
);
}
The component receives a different name value for each instance.
3.2 Reusable Product Card Example
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
function ProductCard({ title, price, category }) {
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
<Text>Category: {category}</Text>
<Text>Price: ₹{price}</Text>
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
marginVertical: 8,
borderRadius: 8,
backgroundColor: '#F2F2F2'
},
title: {
fontSize: 18,
fontWeight: 'bold'
}
});
export default ProductCard;
Use the component with different data:
<ProductCard
title="Wireless Headphones"
price={2499}
category="Electronics"
/>
<ProductCard
title="Travel Backpack"
price={1799}
category="Accessories"
/>
3.3 Props Best Practices
- Use descriptive names such as
title, price, and onPress.
- Pass only the data a component needs.
- Keep props read-only; do not directly modify the props object.
- Use sensible defaults for optional props.
- Document expected prop types and behavior for shared components.
- Consider TypeScript interfaces or types for larger projects.
3.4 Using TypeScript Props
import React from 'react';
import { Text } from 'react-native';
type GreetingProps = {
name: string;
subtitle?: string;
};
function Greeting({ name, subtitle }: GreetingProps) {
return (
<>
<Text>Hello, {name}!</Text>
{subtitle ? <Text>{subtitle}</Text> : null}
</>
);
}
export default Greeting;
TypeScript helps identify incorrect prop values during development and makes shared component contracts clearer.
4. Building a Reusable Button Component
Buttons are common reusable elements in mobile applications. A well-designed button can accept a label, an event handler, and a disabled state.
import React from 'react';
import { Pressable, Text, StyleSheet } from 'react-native';
function AppButton({
title,
onPress,
disabled = false
}) {
return (
<Pressable
onPress={onPress}
disabled={disabled}
accessibilityRole="button"
accessibilityState={{ disabled }}
style={({ pressed }) => [
styles.button,
pressed && !disabled && styles.pressed,
disabled && styles.disabled
]}
>
<Text style={styles.label}>{title}</Text>
</Pressable>
);
}
const styles = StyleSheet.create({
button: {
paddingVertical: 12,
paddingHorizontal: 18,
backgroundColor: '#2563EB',
borderRadius: 8,
alignItems: 'center'
},
pressed: {
opacity: 0.75
},
disabled: {
opacity: 0.45
},
label: {
color: '#FFFFFF',
fontWeight: 'bold',
fontSize: 16
}
});
export default AppButton;
Example usage:
<AppButton
title="Save Profile"
onPress={saveProfile}
/>
<AppButton
title="Submit"
onPress={submitForm}
disabled={isSubmitting}
/>
This approach keeps button appearance consistent while allowing each screen to provide its own action.
5. Reusable Components with State and Events
Reusable components can receive event handlers through props. A component should generally communicate user actions to its parent through callbacks rather than directly controlling unrelated application data.
import React from 'react';
import { View, Text, Pressable } from 'react-native';
function CounterControls({ count, onIncrease, onDecrease }) {
return (
<View>
<Text>Count: {count}</Text>
<Pressable onPress={onIncrease}>
<Text>Increase</Text>
</Pressable>
<Pressable onPress={onDecrease}>
<Text>Decrease</Text>
</Pressable>
</View>
);
}
export default function CounterScreen() {
const [count, setCount] = React.useState(0);
return (
<CounterControls
count={count}
onIncrease={() => setCount(value => value + 1)}
onDecrease={() => setCount(value => value - 1)}
/>
);
}
The parent owns the count state, while the child displays the value and reports user actions. This separation makes the child easier to reuse in other screens.
6. Component Composition and Children
Composition means combining smaller components to build larger interfaces. React supports this pattern through nested components and the special children prop.
6.1 Using the Children Prop
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
function InfoCard({ title, children }) {
return (
<View style={styles.card}>
<Text style={styles.title}>{title}</Text>
{children}
</View>
);
}
const styles = StyleSheet.create({
card: {
padding: 16,
marginVertical: 8,
borderRadius: 10,
backgroundColor: '#FFFFFF'
},
title: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 8
}
});
export default InfoCard;
Example usage:
<InfoCard title="Account Details">
<Text>Name: Aarav Sharma</Text>
<Text>Status: Active</Text>
</InfoCard>
<InfoCard title="Order Summary">
<Text>Items: 3</Text>
<Text>Total: ₹2,500</Text>
</InfoCard>
The card manages the shared layout, while its parent supplies the content. This pattern is useful for profiles, summaries, settings sections, and dashboards.
6.2 Composition Versus Configuration
Configuration uses props to control a component's options, such as a button's title or disabled state. Composition allows a parent to insert custom child content. Use simple props for straightforward differences and composition when the content or layout needs greater flexibility.
7. Organizing a React Native Project
A predictable folder structure helps developers locate components, styles, assets, and screens. The ideal structure depends on the application's size and the team's conventions.
MyApp/
├── src/
│ ├── components/
│ │ ├── AppButton.js
│ │ ├── UserCard.js
│ │ └── InfoCard.js
│ ├── screens/
│ │ ├── HomeScreen.js
│ │ └── ProfileScreen.js
│ ├── hooks/
│ ├── services/
│ ├── utils/
│ └── constants/
├── assets/
├── App.js
└── package.json
- components/: Shared UI elements used across screens.
- screens/: Larger screen-level components.
- hooks/: Custom hooks for reusable stateful logic.
- services/: API clients and external-service integrations.
- utils/: Reusable utility functions.
- constants/: Shared configuration values and fixed labels.
- assets/: Images, fonts, and other static resources.
For a small project, a simpler structure may be sufficient. Add folders when they improve navigation and maintainability rather than following a structure mechanically.
7.1 Exporting and Importing Components
Components can be exported as default exports or named exports. Keep import and export styles consistent within a project.
// Default export
export default function ProfileCard() {
return <Text>Profile</Text>;
}
// Import a default export
import ProfileCard from './ProfileCard';
// Named export
export function SectionTitle() {
return <Text>Section</Text>;
}
// Import a named export
import { SectionTitle } from './SectionTitle';
Learn more from the official React guide to importing and exporting components.
8. React Best Practices: Component Design
8.1 Keep Components Focused
Each component should have a clear responsibility. A component that displays a profile card should not also manage unrelated authentication, analytics, and network synchronization logic.
Recommended: Separate profile presentation, data retrieval, and form submission into appropriate components or modules when the complexity warrants it.
8.2 Prefer Small, Readable Components
Large components with deeply nested conditions and many responsibilities are difficult to understand and test. Break them into smaller components when doing so makes the interface easier to reason about.
8.3 Use Clear Naming
- Use PascalCase for React component names, such as
ProfileCard.
- Choose names that describe purpose, such as
SearchInput or OrderSummary.
- Use descriptive callback names, such as
onSave and onDelete.
- Avoid vague names such as
Thing, Data1, or Component2.
8.4 Avoid Duplicating Logic
When multiple components repeat the same behavior, consider extracting a shared function or custom hook. Keep UI-specific logic in components when it belongs there, and avoid creating abstractions for code that is not meaningfully shared.
8.5 Avoid Over-Engineering
Not every component needs a configuration system, a custom hook, and several layers of abstraction. Start with a straightforward implementation and refactor when a real reuse or maintenance need appears.
8.6 Keep Component Definitions at the Top Level
Define reusable components outside other component functions. Defining a component inside another component can create a new component type during rendering, which can lead to unnecessary remounting and loss of local state.
// Recommended
function ProfileCard({ name }) {
return <Text>{name}</Text>;
}
function ProfileScreen() {
return <ProfileCard name="Aarav" />;
}
9. Props, State, and Data Flow Best Practices
9.1 Keep Props Immutable
Props are inputs received from a parent component. A child component should not modify props directly. If data needs to change, the component that owns the state should update it and pass the updated value down.
Incorrect approach:
function UserProfile({ user }) {
user.name = 'Updated Name';
return <Text>{user.name}</Text>;
}
Recommended approach:
function UserProfile({ user }) {
return <Text>{user.name}</Text>;
}
Update the user object in the component that owns its state, creating a new object instead of mutating the existing one.
9.2 Use State for Changing Data
Use React state when a value changes because of user interaction, an API response, or another application event. Avoid ordinary variables as substitutes for state when the UI must update after the value changes.
import React, { useState } from 'react';
import { View, Text, Pressable } from 'react-native';
function LikeButton() {
const [liked, setLiked] = useState(false);
return (
<View>
<Text>{liked ? 'Liked' : 'Not liked'}</Text>
<Pressable onPress={() => setLiked(value => !value)}>
<Text>{liked ? 'Unlike' : 'Like'}</Text>
</Pressable>
</View>
);
}
export default LikeButton;
9.3 Follow One-Way Data Flow
In React, data commonly flows from parent components to child components through props. Children can notify parents about user actions through callback functions.
- The parent owns data that multiple children need to share.
- The child receives the information it needs through props.
- The child calls a callback when an action should be handled by the parent.
- The parent updates state and passes new values back to its children.
This pattern makes it easier to understand where data comes from and which component is responsible for changing it.
10. Styling Best Practices
10.1 Use StyleSheet for Shared Styles
React Native's StyleSheet API provides an organized way to define styles outside JSX markup. Reusable components can keep their styles near their implementation. See the official React Native styling documentation.
import React from 'react';
import { StyleSheet, View, Text } from 'react-native';
function SectionTitle({ children }) {
return (
<View style={styles.container}>
<Text style={styles.title}>{children}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
paddingVertical: 12
},
title: {
fontSize: 20,
fontWeight: 'bold'
}
});
export default SectionTitle;
10.2 Create Shared Design Values
Applications often use consistent colors, spacing, typography, and border radii. Store frequently reused values in a shared constants or theme module when it improves consistency.
// src/constants/theme.js
export const colors = {
primary: '#2563EB',
background: '#FFFFFF',
text: '#1F2937',
muted: '#6B7280',
danger: '#DC2626'
};
export const spacing = {
small: 8,
medium: 16,
large: 24
};
Import these values into multiple components rather than repeatedly entering the same values by hand.
10.3 Avoid Unnecessary Inline Style Duplication
Inline styles are appropriate for simple dynamic values. However, large repeated style objects are usually easier to maintain when extracted into named styles or a shared theme.
Do not move every one-off style into a global file automatically. Keep styles close to the component when they are specific to that component.
11. Conditional Rendering and Component Reuse
Conditional rendering allows components to display different content based on props or state. It is useful for loading indicators, error messages, empty states, and authenticated versus unauthenticated screens.
import React from 'react';
import { View, Text, ActivityIndicator } from 'react-native';
function LoadingState({ loading, error, children }) {
if (loading) {
return (
<View>
<ActivityIndicator size="large" />
<Text>Loading...</Text>
</View>
);
}
if (error) {
return <Text>Unable to load data. Please try again.</Text>;
}
return <View>{children}</View>;
}
export default LoadingState;
A screen can now use the same component to manage its loading, error, and success presentation.
<LoadingState loading={isLoading} error={hasError}>
<Text>Profile loaded successfully.</Text>
</LoadingState>
For real applications, consider accepting an error message or retry callback instead of hardcoding error content.
12. Rendering Lists of Reusable Components
Lists are common in mobile applications, including product catalogs, messages, contacts, and notifications. React Native provides FlatList for efficiently rendering scrollable collections.
import React from 'react';
import { FlatList, View, Text, StyleSheet } from 'react-native';
const users = [
{ id: '1', name: 'Aarav' },
{ id: '2', name: 'Priya' },
{ id: '3', name: 'Rohan' }
];
function UserListItem({ name }) {
return (
<View style={styles.item}>
<Text>{name}</Text>
</View>
);
}
export default function UserListScreen() {
return (
<FlatList
data={users}
keyExtractor={item => item.id}
renderItem={({ item }) => (
<UserListItem name={item.name} />
)}
/>
);
}
const styles = StyleSheet.create({
item: {
padding: 16,
borderBottomWidth: 1,
borderBottomColor: '#DDDDDD'
}
});
12.1 Why Stable Keys Matter
Each list item should have a stable, unique key so React can identify items when the list changes. Prefer an existing unique ID from your data rather than an array index when items can be inserted, removed, or reordered.
12.2 List Performance Tips
- Use
FlatList for long or changing collections rather than rendering every item inside a large ScrollView.
- Keep row components focused and avoid expensive calculations during rendering.
- Use stable keys and update list data immutably.
- Consider
getItemLayout when row dimensions are fixed and measurement is unnecessary.
- Measure actual performance before adding memoization or complex optimization techniques.
13. Accessibility Best Practices
Reusable components should support people who interact with applications using screen readers, larger text, or alternative input methods. Accessibility is easier to maintain when it is built into shared UI components from the beginning.
- Give buttons meaningful labels and appropriate accessibility roles.
- Communicate disabled, selected, and checked states when applicable.
- Do not rely on color alone to communicate errors or status.
- Use readable text sizes and sufficient contrast.
- Ensure interactive controls have practical touch targets.
- Test important screens with platform accessibility tools.
<Pressable
accessibilityRole="button"
accessibilityLabel="Save profile"
accessibilityHint="Saves your profile changes"
onPress={handleSave}
>
<Text>Save</Text>
</Pressable>
Ensure accessibility labels accurately describe the action and do not unnecessarily repeat text already announced by the screen reader.
14. Error Handling and Maintainability
Reliable components should handle expected situations such as missing optional data, failed requests, empty lists, and disabled actions. The correct response depends on the component's purpose.
14.1 Use Sensible Defaults
import React from 'react';
import { Text } from 'react-native';
function ProfileLabel({ name = 'Guest' }) {
return <Text>Welcome, {name}</Text>;
}
export default ProfileLabel;
A default value can improve usability when a prop is optional. Do not hide required-data problems behind arbitrary defaults; validate required information where appropriate.
14.2 Keep API Calls Out of Pure Presentation Components
A component that only displays a profile should not need to know how the application retrieves that profile. A screen, service, or custom hook can handle data retrieval and pass the resulting data and actions into the presentation component.
This separation can make components easier to reuse with local data, remote data, mock data, and automated tests.
14.3 Handle Loading, Empty, and Error States
Data-driven components should account for common states instead of assuming that content always exists. For example, a product list may need a loading indicator, an empty-state message, and an error message with a retry action.
15. Performance Optimization Best Practices
Performance improvements should be guided by measurements. React Native's official performance guidance explains how to investigate slow frames and why performance should be checked in production builds, since development mode can affect performance. See the React Native Performance Overview.
15.1 Avoid Unnecessary Work During Rendering
Keep rendering logic straightforward. Avoid expensive calculations, synchronous heavy processing, and unrelated side effects during render.
15.2 Use React.memo When Appropriate
React.memo can skip rendering a function component when its props have not changed according to its comparison. It is most useful when a component renders often with unchanged props and its rendering cost matters.
import React from 'react';
import { View, Text } from 'react-native';
const ProductTitle = React.memo(function ProductTitle({ title }) {
return (
<View>
<Text>{title}</Text>
</View>
);
});
export default ProductTitle;
Memoization is an optimization, not a requirement for every component. It may provide little benefit when a component is inexpensive or its props change frequently.
15.3 Understand useMemo and useCallback
useMemo can cache the result of an expensive calculation between renders while its dependencies remain unchanged.
useCallback can preserve a function reference between renders while its dependencies remain unchanged.
import React, { useMemo, useCallback, useState } from 'react';
function SearchExample({ products }) {
const [query, setQuery] = useState('');
const filteredProducts = useMemo(() => {
const normalizedQuery = query.trim().toLowerCase();
return products.filter(product =>
product.name.toLowerCase().includes(normalizedQuery)
);
}, [products, query]);
const handleClear = useCallback(() => {
setQuery('');
}, []);
return null;
}
This snippet demonstrates the hooks but does not display the filtered products. In a real component, render the results and connect handleClear to a control. For small datasets, straightforward filtering may be sufficient without useMemo.
15.4 Avoid Premature Optimization
First write clear and correct code. Then profile the application, identify bottlenecks, and optimize the areas that materially affect the user experience. Excessive memoization can make code harder to understand without producing a meaningful improvement.
16. Testing Reusable Components
Reusable components can be tested independently to verify their visible output and behavior. Tests should focus on what users can observe rather than implementation details whenever practical.
16.1 What Should You Test?
- Whether the expected text and content are displayed.
- Whether pressing a button invokes the supplied callback.
- Whether disabled controls behave correctly.
- Whether conditional states such as loading and errors display properly.
- Whether important accessibility labels and roles are present.
16.2 Example Test with React Native Testing Library
The following example assumes that React Native Testing Library and a compatible Jest configuration are installed in the project.
import React from 'react';
import { render, fireEvent } from '@testing-library/react-native';
import AppButton from '../components/AppButton';
test('calls onPress when the button is pressed', () => {
const onPress = jest.fn();
const { getByRole } = render(
<AppButton title="Save" onPress={onPress} />
);
fireEvent.press(getByRole('button'));
expect(onPress).toHaveBeenCalledTimes(1);
});
Also test the disabled state and any special behavior the component promises to support.
17. Common Mistakes to Avoid
| Mistake |
Why It Is a Problem |
Better Practice |
| Repeating the same UI in many screens |
Changes must be made in several places. |
Create a shared component when repetition justifies it. |
| Making components responsible for too many tasks |
Code becomes difficult to understand and test. |
Separate presentation, data handling, and unrelated behavior. |
| Mutating props or state directly |
It can cause unpredictable rendering and data changes. |
Use state setters and immutable updates. |
| Using unclear prop names |
Component behavior is harder to understand. |
Choose descriptive, consistent names. |
| Creating abstractions too early |
Extra layers make simple code harder to maintain. |
Refactor when a clear reuse or design need emerges. |
| Using array indexes as keys for changing lists |
Items can be incorrectly associated after reordering. |
Use stable, unique item identifiers. |
| Memoizing every component |
It adds complexity without guaranteed speed gains. |
Profile and optimize measured bottlenecks. |
| Ignoring accessibility |
Some users may struggle to operate the interface. |
Include labels, roles, states, and accessibility testing. |
| Testing only the complete screen |
Individual component problems can be harder to isolate. |
Test shared components and critical user flows. |
18. Practical Project: Reusable Profile and Settings Screen
Project Objective
Create a simple React Native profile screen using reusable components, props, state, event handlers, and consistent styling.
18.1 Requirements
- Create a reusable
SectionTitle component.
- Create a reusable
AppButton component.
- Create a
ProfileCard component that accepts a name and email.
- Display profile details and a settings section.
- Add an edit button that toggles an editing state.
- Add a save button that displays a confirmation message.
- Provide suitable accessibility labels for interactive controls.
18.2 Example Implementation
import React, { useState } from 'react';
import {
View,
Text,
TextInput,
Pressable,
StyleSheet
} from 'react-native';
function SectionTitle({ children }) {
return <Text style={styles.sectionTitle}>{children}</Text>;
}
function ProfileCard({ name, email }) {
return (
<View style={styles.card}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.email}>{email}</Text>
</View>
);
}
function AppButton({ title, onPress }) {
return (
<Pressable
accessibilityRole="button"
onPress={onPress}
style={styles.button}
>
<Text style={styles.buttonText}>{title}</Text>
</Pressable>
);
}
export default function ProfileScreen() {
const [name, setName] = useState('Aarav Sharma');
const [email] = useState('[email protected]');
const [isEditing, setIsEditing] = useState(false);
const [message, setMessage] = useState('');
function handleSave() {
setIsEditing(false);
setMessage('Profile saved successfully.');
}
return (
<View style={styles.container}>
<SectionTitle>My Profile</SectionTitle>
{isEditing ? (
<TextInput
accessibilityLabel="Profile name"
value={name}
onChangeText={setName}
style={styles.input}
placeholder="Enter your name"
/>
) : (
<ProfileCard name={name} email={email} />
)}
{isEditing ? (
<AppButton title="Save Profile" onPress={handleSave} />
) : (
<AppButton
title="Edit Profile"
onPress={() => {
setMessage('');
setIsEditing(true);
}}
/>
)}
<SectionTitle>Settings</SectionTitle>
<Text>Manage your account preferences here.</Text>
{message ? (
<Text accessibilityLiveRegion="polite">{message}</Text>
) : null}
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#FFFFFF'
},
sectionTitle: {
fontSize: 22,
fontWeight: 'bold',
marginBottom: 12,
marginTop: 16
},
card: {
padding: 16,
borderRadius: 10,
backgroundColor: '#F3F4F6',
marginBottom: 12
},
name: {
fontSize: 18,
fontWeight: 'bold'
},
email: {
fontSize: 14,
marginTop: 6
},
input: {
borderWidth: 1,
borderColor: '#D1D5DB',
borderRadius: 8,
padding: 12,
marginBottom: 12
},
button: {
backgroundColor: '#2563EB',
borderRadius: 8,
padding: 12,
alignItems: 'center',
marginVertical: 8
},
buttonText: {
color: '#FFFFFF',
fontWeight: 'bold'
}
});
18.3 Project Explanation
- SectionTitle: Reuses the same heading style for different sections.
- ProfileCard: Displays profile information through props.
- AppButton: Provides consistent button styling and accepts an event callback.
- ProfileScreen: Owns the editing state and passes information to its child components.
- TextInput: Updates the profile name through the
setName state setter.
- Save action: Exits editing mode and displays a confirmation message.
Important: This is a learning example. It updates local component state only; it does not persist changes to a database or remote API. A production app should add validation, error handling, and persistent storage.
19. Practice Exercises
- Create a reusable
PrimaryButton that accepts a title, callback, and disabled state.
- Build a
ProductCard that accepts a product name, price, and category.
- Create a reusable
EmptyState component for displaying a message when a list has no items.
- Create a
NotificationItem component and render multiple items using FlatList.
- Build a
SearchInput component that receives its value and change handler through props.
- Add loading and error states to a reusable data display component.
- Write a test that verifies a reusable button invokes its callback.
- Review an existing screen and identify duplicated UI that could be extracted into components.
20. Interview Questions and Answers
Q1. What is a reusable component in React Native?
A reusable component is a UI building block that can be used in multiple places. It reduces duplication and encourages consistent design and behavior.
Q2. What are the main advantages of reusable components?
They improve maintainability, readability, consistency, testability, and the ability to extend an application.
Q3. What are props?
Props are inputs passed from a parent component to a child component. They let developers customize a component's content and behavior.
Q4. What is the difference between props and state?
Props are supplied by a parent component, while state is managed by a component or another designated state owner. State is useful for data that changes over time and causes the UI to update.
Q5. What is component composition?
Component composition means combining smaller components to build larger interfaces. The children prop is one common way to create flexible layouts.
Q6. Why should components have a single clear responsibility?
Focused components are easier to understand, reuse, test, debug, and maintain.
Q7. What is the purpose of React.memo?
React.memo can skip a function component's render when its props have not changed according to its comparison. It should be used when it provides a meaningful performance benefit.
Q8. What is the difference between useMemo and useCallback?
useMemo caches a calculation result, while useCallback caches a function definition between renders while its dependencies remain unchanged.
Q9. Why are stable keys important in FlatList?
Stable keys help React identify list items correctly when items are inserted, removed, or reordered.
Q10. How can you improve reusable component accessibility?
Use meaningful accessibility labels, roles, and state information; ensure readable text and sufficient contrast; and test with screen readers.
Q11. Should every repeated JSX fragment become a component?
No. Create a component when reuse, clarity, testing, or independent responsibility makes the abstraction valuable. Avoid adding components that make the code more complicated without a clear benefit.
Q12. How do you decide whether to optimize a component?
Measure performance first, identify the actual bottleneck, and then consider techniques such as simplifying rendering, React.memo, useMemo, or useCallback where appropriate.
21. Quick Revision Checklist
- Understand what reusable components are and when to create them.
- Know how to pass data and callbacks through props.
- Use state for values that change and need to update the UI.
- Keep props and state immutable.
- Use composition and the
children prop to build flexible layouts.
- Organize files according to project size and complexity.
- Use consistent naming and shared design values where useful.
- Render long collections with
FlatList and stable keys.
- Include loading, empty, and error states where necessary.
- Design shared components with accessibility in mind.
- Test component behavior and optimize based on measurements.
- Avoid unnecessary abstractions and premature optimization.
22. Official Learning Resources
23. Conclusion
Reusable components and React best practices are essential for building maintainable React Native applications. Components help divide an interface into clear building blocks, while props make those building blocks flexible and state enables interactive behavior. Composition, consistent styling, sensible project organization, accessibility, testing, and performance measurement help keep an application reliable as it grows.
Practice by identifying repeated UI patterns, extracting focused components, passing data through props, and testing the resulting behavior. Start with simple solutions and add abstraction or optimization only when it improves clarity, reuse, or performance.
Explore React Native Training: View React Native Training Course
Register for a Demo: Book a Course Demo
Visit JustAcademy: https://www.justacademy.co/